#include <assert.h>

#include <atomic>
#include <iostream>
#include <thread>
#include <vector>

struct X {
  int i;
  std::string s;
};

std::atomic<X*> p;
std::atomic<int> a;

// 这个例子中use_x中的p.load carries-a-dependency-to x,
// use_x中的consume只能保证x的值是被flush的，
// 也就是说assert(x->i==42);和assert(x->s==”hello”);是不会fired，
// 但是assert(a.load(std::memory_order_relaxed)==99); 则有可能被fired
// 简单点说就是consume的特性只会对其carries-a-dependency-to的变量具有synchronsizes-with功能

// x是个指针，依赖2个数据，int i=42, string s=”hello” , #3循环，直到#2 x被store，
// 那么在相应的依赖数据也设置好了，所以在#4,#5的断言也就可以通过。但a没有依赖，且是relaxed，无法判定断言

void create_x() {
  X* x = new X;
  x->i = 42;
  x->s = "hello";
  a.store(99, std::memory_order_relaxed);  // 1
  p.store(x, std::memory_order_release);   // 2
}

void use_x() {
  X* x;
  while (!(x = p.load(std::memory_order_consume)))  // 3
    std::this_thread::sleep_for(std::chrono::microseconds(1));
  assert(x->i == 42);                               // 4
  assert(x->s == "hello");                          // 5
  assert(a.load(std::memory_order_relaxed) == 99);  // 6
}

int main() {
  std::thread t1(create_x);
  std::thread t2(use_x);
  t1.join();
  t2.join();

  return 0;
}